// #include <myhead_for_app.h>
// #include <myhead.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<unistd.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<dirent.h>
// #include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<sys/socket.h>
#include<netinet/ip.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <signal.h>
#include <wait.h>
#include <time.h>
#include <sys/time.h>

#include <pthread.h>
#include "./usr/inc/threadpool.h"
#include "./usr/inc/mydbop.h"
#include "./usr/inc/hr_manager.h"
#include "./usr/inc/myprotocol.h"
// #include "manager.h"

sqlite3 *db = NULL;
sem_t sem;

fd_set readfds_save;
fd_set readfds_modify;

// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void mytask(void *val)
{
    int connect_fd = *(int *)val; // 要拷贝一份
    char buf[512] = {0};
    int ret = recv(connect_fd, buf, sizeof(buf), 0);
    if (0 == ret)
    {
        printf("客户端断开连接\n");
        close(connect_fd);
        FD_CLR(connect_fd, &readfds_save);
        sem_post(&sem);
    }
    else if (-1 == ret)
    {
        sem_post(&sem);
        printf("recv error\n");
    }
    else
    {
        sem_post(&sem);
        int choose;
        char choose_s[5] = {0};
        memcpy(choose_s, buf, 2);
        choose = atoi(choose_s);
        trans_usrinfo_t recv_usrinfo;
        trans_usrinfo_t send_usrinfo;
        trans_dbinfo_t recv_dbinfo;
        trans_dbinfo_t send_dbinfo;
        char recv_info[512] = {0};
        char send_info[512] = {0};
        memcpy(recv_info, buf + 2, sizeof(recv_info));
        search_info_t search_info = {0};
        int res = 0;
        switch (choose)
        {
        case hrlogin_protocol: // hr的登录请求
            memcpy(&recv_usrinfo, buf + 2, sizeof(recv_usrinfo));
            if (hr_login_verify(&recv_usrinfo, db))
            {
                // printf("登录成功\n");
                sprintf(send_info, "%d%s", hrlogin_verify_protocol, "yes");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // printf("登录失败\n");
                sprintf(send_info, "%d%s", hrlogin_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case add_protocol: // 添加员工信息的请求
            memcpy(&recv_dbinfo, buf + 2, sizeof(recv_dbinfo));
            res = db_insert_staff_info(db, recv_dbinfo);
            if (-2 == res)
            {
                sprintf(send_info, "%d%s", add_verify_protocol, "exist error!");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else if (-1 == res)
            {
                sprintf(send_info, "%d%s", add_verify_protocol, "error!");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                sprintf(send_info, "%d%s", add_verify_protocol, "ok");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case query_request_protocol: // 查询员工信息的请求
            memcpy(&recv_dbinfo, buf + 2, sizeof(recv_dbinfo));
            strcpy(search_info.name, recv_dbinfo.name);
            res = db_search(db, &search_info);
            if (-1 == res)
            {
                sprintf(send_info, "%d%s", search_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // 发数据
                sprintf(send_info, "%d", search_verify_protocol);
                memcpy(send_info + 2, &search_info.staff_info, sizeof(search_info.staff_info));
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case modify_request_protocol:
            memcpy(&recv_dbinfo, buf + 2, sizeof(recv_dbinfo));
            res = db_modify_staff_info(db, recv_dbinfo);
            if (res)
            {
                // 修改失败
                sprintf(send_info, "%d%s", modify_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // 修改成功
                sprintf(send_info, "%d%s", modify_verify_protocol, "ok");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case delete_request_protocol:
            memcpy(&search_info, buf + 2, sizeof(search_info));
            res = db_delete_staff_info(db, &search_info);
            if (res)
            {
                // 删除失败
                sprintf(send_info, "%d%s", delete_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // 删除成功
                sprintf(send_info, "%d%s", delete_verify_protocol, "ok");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case select_all_request_protocol:
            // 查询所有员工信息
            res = db_select_all(db, connect_fd);
            break;
        case managerlogin_protocol: // 管理员的登录请求
            memcpy(&recv_usrinfo, buf + 2, sizeof(recv_usrinfo));
            if (manager_login_verify(&recv_usrinfo, db))
            {
                // printf("登录成功\n");
                sprintf(send_info, "%d%s", managerlogin_verify_protocol, "yes");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // printf("登录失败\n");
                sprintf(send_info, "%d%s", managerlogin_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case register_request_protocol:
            memcpy(&recv_usrinfo, buf + 2, sizeof(recv_usrinfo));
            if (!register_usr(&recv_usrinfo, db))
            {
                // printf("注册成功\n");
                sprintf(send_info, "%d%s", register_verify_protocol, "ok");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // printf("注册失败\n");
                sprintf(send_info, "%d%s", register_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case delete_usr_request_protocl:
            memcpy(&recv_usrinfo, buf + 2, sizeof(recv_usrinfo));
            if (!delete_usr(&recv_usrinfo, db))
            {
                // printf("删除成功\n");
                sprintf(send_info, "%d%s", delete_usr_verify_protocl, "ok");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // printf("删除失败\n");
                sprintf(send_info, "%d%s", delete_usr_verify_protocl, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case managerquery_request_protocol:
            memcpy(&recv_dbinfo, buf + 2, sizeof(recv_dbinfo));
            strcpy(search_info.name, recv_dbinfo.name);
            res = db_search(db, &search_info);
            if (-1 == res)
            {
                sprintf(send_info, "%d%s", managerquery_verify_protocol, "no");
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            else
            {
                // 发数据
                sprintf(send_info, "%d", managerquery_verify_protocol);
                memcpy(send_info + 2, &search_info.staff_info, sizeof(search_info.staff_info));
                send(connect_fd, send_info, sizeof(send_info), 0);
            }
            break;
        case select_allusr_request_protocol:
            res = db_select_allusr(db, connect_fd);
            break;
        default:
            break;
        }
    }
    // return NULL;
}

int main(int argc, char const *argv[])
{
    db = db_init();

    if (3 != argc)
    {
        printf("Usage: %s <ip> <port>\n", argv[0]);
        return -1;
    }

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
        exit(-1);
        // PRINT_ERROR("socket error");
    struct sockaddr_in service_addr;
    service_addr.sin_addr.s_addr = inet_addr(argv[1]);
    service_addr.sin_port = htons(atoi(argv[2]));
    service_addr.sin_family = AF_INET;
    if (bind(sockfd, (struct sockaddr *)&service_addr, sizeof(service_addr)))
        exit(-1);
        // PRINT_ERROR("bind error");
    if (listen(sockfd, 3))
        exit(-1);
        // PRINT_ERROR("listen error");

    printf("服务器启动成功\n");

    pthread_t tid;
    sem_init(&sem, 0, 0);

    // create_pool(5);
    threadpool_t *pool = threadpool_create(4, 8);
    if (pool == NULL)
    {
        printf("Failed to create a thread pool.\n");
        return -1;
    }

    FD_ZERO(&readfds_save);
    FD_ZERO(&readfds_modify);
    FD_SET(sockfd, &readfds_save);
    int max_fd = sockfd;

    while (1)
    {

        readfds_modify = readfds_save;
        int nfd = select(max_fd + 1, &readfds_modify, NULL, NULL, NULL);
        if (nfd == -1)
            exit(-1);
            // PRINT_ERROR("select error");

        for (int eventfd = 3; eventfd < max_fd + 1; eventfd++)
        {
            if (FD_ISSET(eventfd, &readfds_modify))
            {
                if (eventfd == sockfd)
                {
                    int connect_fd = accept(sockfd, NULL, NULL);
                    if (-1 == connect_fd)
                        exit(-1);
                        // PRINT_ERROR("accept error");
                    else
                    {
                        printf("有新的客户端连接\n");
                        FD_SET(connect_fd, &readfds_save);
                        max_fd = max_fd > connect_fd ? max_fd : connect_fd;
                    }
                }
                else
                {
                    // add_work(mytask, &eventfd);
                    threadpool_add(pool, mytask, &eventfd);

                    sem_wait(&sem);
                }
            }
        }
    }

    close(sockfd);
    // destory_pool();
    threadpool_destroy(pool, 0);
    return 0;
}
